/**
 *    Copyright 2012 Geensoft S.A.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
package ar.com.greensoft.neo.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.richfaces.model.ArrangeableState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import ar.com.greensoft.neo.dao.DaoException;
import ar.com.greensoft.neo.dao.GroupDao;
import ar.com.greensoft.neo.model.Group;
import ar.com.greensoft.neo.model.GroupAuthorities;
import ar.com.greensoft.neo.model.Group_;
import ar.com.greensoft.neo.search.SearchInput;
import ar.com.greensoft.neo.search.TextSearchInput;
import ar.com.greensoft.neo.util.SearchUtil;

/**
*
* @author Jorge E. Villaverde
* @since 1.0
*/
@Transactional
@Repository
public class JpaGroupDaoImpl implements GroupDao {
	
	@PersistenceContext
	private EntityManager entityManager;
	
	protected static final Logger logger = LoggerFactory.getLogger(JpaGroupDaoImpl.class);

	@Override
	public List<Group> findByName(String name) throws DaoException{
		name = SearchUtil.likeString(name); 
		
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		
		CriteriaQuery<Group> criteriaQuery = criteriaBuilder.createQuery(Group.class);
		Root<Group> root = criteriaQuery.from(Group.class);
		
		criteriaQuery.select(root);
		
		criteriaQuery.where(
				criteriaBuilder.or(
						criteriaBuilder.like(root.get(Group_.name), name)));
					
		TypedQuery<Group> typedQuery = entityManager.createQuery(criteriaQuery);
		
		return typedQuery.getResultList();
	}

	@Override
	public Group findById(Long id) throws DaoException {
		if(logger.isTraceEnabled())
			logger.trace("Returning Group with id: " + id);
		return entityManager.find(Group.class, id);
	}

	@Override
	public List<Group> findAll() throws DaoException {
		if(logger.isTraceEnabled())
			logger.trace("Returning the list of Groups");
		TypedQuery<Group> query = entityManager.createNamedQuery(Group.FIND_ALL_QUERY_NAME, Group.class);	
		return query.getResultList();
	}

	@Override
	public List<Group> findEntries(int startPosition, int maxResult) throws DaoException {
		if(logger.isTraceEnabled())
			logger.trace("Returning the list of Groups from: " + startPosition + " to " + (startPosition+maxResult));

		TypedQuery<Group> query = entityManager.createNamedQuery(Group.FIND_ALL_QUERY_NAME, Group.class);

		query.setFirstResult(startPosition);
		query.setMaxResults(maxResult);
		
		return query.getResultList();
	}

	@Override
	public Group merge(Group persistentObject) throws DaoException {
		if(logger.isTraceEnabled())
			logger.trace("Merging User: " + persistentObject);
		Group mergeEntity = entityManager.merge(persistentObject);
		entityManager.flush();
		return mergeEntity; 
	}

	@Override
	public void persist(Group transientObject) throws DaoException {
		entityManager.persist(transientObject);
	}

	@Override
	public void refresh(Group persistentObject) throws DaoException {
		entityManager.refresh(persistentObject);
	}

	@Override
	public void remove(Group persistentObject) throws DaoException {
		Group entity = entityManager.merge(persistentObject);
		entityManager.remove(entity);
	}

	@Override
	public long count() throws DaoException {
		if(logger.isTraceEnabled())
			logger.trace("Counting Users in the Repository");
		return (Long)entityManager.createNamedQuery(Group.COUNT_QUERY_NAME).getSingleResult();
	}

	@Override
	public List<Group> findEntriesBySearchInput(SearchInput input, int startPosition, int maxResult) throws DaoException {
		if(logger.isTraceEnabled())
			logger.trace("Returning the list of Entities from: " + startPosition + " to " + (startPosition+maxResult) + " by SeachInput");

		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		
		CriteriaQuery<Group> criteriaQuery = criteriaBuilder.createQuery(Group.class);
		Root<Group> root = criteriaQuery.from(Group.class);
		
		criteriaQuery.select(root);
		Expression<Boolean> where = createWhereFromSearchInput(input, root);
		if(where != null)
			criteriaQuery.where(where);

		TypedQuery<Group> typedQuery = entityManager.createQuery(criteriaQuery);
		typedQuery.setFirstResult(startPosition);
		typedQuery.setMaxResults(maxResult);
		
		return typedQuery.getResultList();
	}

	@Override
	public long countBySearchInput(SearchInput input) throws DaoException {
		if(logger.isTraceEnabled())
			logger.trace("Counting Entities in the Repository by Search Input");
		
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);

		Root<Group> root = criteriaQuery.from(Group.class);
		
		criteriaQuery.select(criteriaBuilder.count(root));
		Expression<Boolean> where = createWhereFromSearchInput(input, root);
		if(where != null)
			criteriaQuery.where(where);
		
		TypedQuery<Long> typedQuery = entityManager.createQuery(criteriaQuery);
		
		return typedQuery.getSingleResult();
	}
	
	protected Expression<Boolean> createWhereFromSearchInput(SearchInput input, Root<Group> root) {
		TextSearchInput tsi = (TextSearchInput)input;
		
		if(tsi == null)
			return null;
		if(!StringUtils.hasText(tsi.getText()))		
			return null;

		String searchText = SearchUtil.likeString(tsi.getText());
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		
		Predicate predicate = criteriaBuilder.like(
				root.get(Group_.name), searchText);
		
		return predicate;
	}

	@Override
	public void addAuthority(GroupAuthorities ga) throws DaoException {
		if(logger.isTraceEnabled())
			logger.trace("Granting Authority: " + ga.getAuthority() + " for Group: " + ga.getGroup().getName());
		entityManager.persist(ga);
	}

	@Override
	public List<Group> findEntries(ArrangeableState state, int startPosition,
			int maxResult) throws DaoException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long countByArrangeableState(ArrangeableState state)
			throws DaoException {
		// TODO Auto-generated method stub
		return 0;
	}	
}